import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.Vector;

/**
 * Manual implementation of the RSA encryption algorithm
 */
public class RSA {
    
    /**
     * Encrypts/Decrypts a value with RSA
     * @param value The value to be encrypted/decrypted
     * @param key The key to encrypt/decrypt the value
     * @param N
     */
    private BigInteger transformValue(BigInteger value, BigInteger key, BigInteger N) {
        return value.modPow(key,N);
    }
    
    /**
     * Encrypts the message with the given key
     * @param message The original message
     * @param key The key to encrypt the message with
     * @param N
     */
    public String encrypt(String message, BigInteger key, BigInteger N) {
        String encrypted = new String("");
        for(int x = 0; x < message.length(); x++)
            encrypted += transformValue(BigInteger.valueOf(message.charAt(x)),key,N) + "#";
        return encrypted;
    }
    
    /**
     * Decrypts the message with the given key
     * @param message The original message
     * @param key The key to decrypt the message with
     * @param N
     */
    public String decrypt(String message, BigInteger key, BigInteger N) {
        String decrypt = new String("");
        
        StringTokenizer tokenizer = new StringTokenizer(message,"#");
        while(tokenizer.hasMoreTokens()) {
            String str = tokenizer.nextToken();
            decrypt += (char)transformValue(BigInteger.valueOf(Integer.parseInt(str)),key,N).intValue();
        }
        
        return decrypt;
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        try {
            byte [] file = Storage.readFile("g:\\junkdrawer\\original.txt");
            String original = new String(file);//, "UTF8");
            
            RSA rsa = new RSA();
            BigInteger p = Mathematics.generatePrime(10);
            BigInteger q = Mathematics.generatePrime(10);
            BigInteger N = p.multiply(q);
            BigInteger p_minus = p.subtract(BigInteger.ONE);
            BigInteger q_minus = q.subtract(BigInteger.ONE);
            BigInteger phi = p_minus.multiply(q_minus);
            BigInteger e = Mathematics.coprime(phi, N);
            BigInteger d = e.modInverse(phi);
            System.out.println("p: " + p);
            System.out.println("q: " + q);
            System.out.println("N: " + N);
            System.out.println("p-1: " + p_minus);
            System.out.println("q-1: " + q_minus);
            System.out.println("phi: " + phi);
            System.out.println("e: " + e);
            System.out.println("d: " + d);
            Storage.saveFile("g:\\junkdrawer\\after.txt",rsa.decrypt(rsa.encrypt(original,e,N),d,N).getBytes("UTF8"));
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
        }
    }
}
